#include <iostream>
#include <queue>
#include <pthread.h>

template<class T>
class blockqueue
{
private:
    int _cap;//容量
    std::queue<T> _q;//交易场所-临界资源
    //同步与互斥
    pthread_cond_t _data;
    pthread_cond_t _space;
    pthread_mutex_t _lock;
    //pthread_mutex_t c_lock;
    //pthread_mutex_t p_lock;

public:
    blockqueue(int cap):_cap(cap)
    {
        pthread_cond_init(&_data,nullptr);
        pthread_cond_init(&_space,nullptr);
        pthread_mutex_init(&_lock,nullptr);
        //pthread_mutex_init(&c_lock,nullptr);
        //pthread_mutex_init(&p_lock,nullptr);
    }
    bool IsFull()
    {
        return _q.size()==_cap;
    }
    bool IsEmpty()
    {
        return _q.size()==0;
    }
    //获取数据
    void Get(T* out)
    {
        //pthread_mutex_lock(&c_lock);
        pthread_mutex_lock(&_lock);
        while(IsEmpty())//唤醒后还需检测
        {
            pthread_cond_wait(&_data,&_lock);//同步
        }
        //有数据
        *out=_q.front();
        _q.pop();
        if(_q.size()<=_cap/2)//空间过半
            pthread_cond_signal(&_space);//唤醒该条件变量下的线程
        pthread_mutex_unlock(&_lock);
        //pthread_mutex_unlock(&c_lock);
    }
    //放数据
    void Put(const T& in)
    {
        //pthread_mutex_lock(&p_lock);
        pthread_mutex_lock(&_lock);
        while(IsFull())
        {
            pthread_cond_wait(&_space,&_lock);
        }
        _q.push(in);
        if(_q.size()>=_cap/2)//数据过半
        pthread_cond_signal(&_data);//有数据，唤醒该条件变量下的等待线程
        pthread_mutex_unlock(&_lock);
        //pthread_mutex_unlock(&p_lock);
    }

    ~blockqueue()
    {
        pthread_cond_destroy(&_data);
        pthread_cond_destroy(&_space);
        pthread_mutex_destroy(&_lock);
        //pthread_mutex_destroy(&c_lock);
        //pthread_mutex_destroy(&p_lock);
    }
};
